線上日常攻略讀書會 這次攻略 reactStartKit & Immutable.js
Immutable 可以參考 howard 大大的這篇 blog
https://rhadow.github.io/2015/05/10/flux-immutable/
後半段另外介紹 reactStartKit 這個玩意兒
因為在實務上如果是採用 搭配 express 的方法 通常會都會使用到許多套件,也許不是人人都是nodejs高手不知道要怎樣把一個環境拼起來,變成即戰力,這次介紹reactStartKit 就是會幫你把一些基礎常用的好東東,拼成一台超級跑車,可以省去很多在組裝各種元件的時間.
當然我們也是需要去了解到這個reactStartKit的架構,以免發生問題的時候動彈不得
https://github.com/kriasoft/react-starter-kit 這次要攻略的連結
可以看到他的branch 有幾個版本 這邊我們選擇 feature/react-intl 多國語系版本
來看一下目錄結構
...
docs // 說明文件
public // 輸出編譯後的檔案
src // 主程式
test // 測試
tools // 工具 like webpack 跟 npm 會常用到的指令
...
這邊應為都配置好了 react universal 由以下套件組裝而成的一個好的樣板模式
Node.js, Express, GraphQL, React.js, Babel 6, PostCSS, Webpack, Browsersync
那這邊主要來提一下src 的部分
...
actions // redux
components // 共用元件
constants // 常數宣告
content // 靜態文字
core // 共用部分
data // 資料庫
messages // 多國語系
public // 靜態檔案
reducers // redux
routes // universal
store // redux
client.js // 前端entry
server.js // 後端entry
config.js // 設定檔
...
這邊一開始看還滿複雜,就來慢慢來看嚕
因為是 universal 所以前後端會共用元件 基本 前端會有一個基本固定樣板 這邊可以先理解為 client.js 這一支,這裡面會用到一些技巧去改變 可以讓seo 吃到資料,這是一般在寫spa網站做不到的好處
...
import React from 'react';
import ReactDOM from 'react-dom';
import FastClick from 'fastclick';
import UniversalRouter from 'universal-router';
import queryString from 'query-string';
import { createPath } from 'history/PathUtils';
import { addLocaleData } from 'react-intl';
import en from 'react-intl/locale-data/en';
import cs from 'react-intl/locale-data/cs';
import history from './core/history';
import App from './components/App';
import configureStore from './store/configureStore';
[en, cs].forEach(addLocaleData);
//多國語系,如果有改變重新啟動不會更新一定要commit,否則下次啟動還是一樣
const context = { //把所有的style傳入後組裝
insertCss: (...styles) => { //es6 語法可以理解把所有style傳入
const removeCss = styles.map(x => x._insertCss());
return () => { removeCss.forEach(f => f()); };
},
store: configureStore(window.APP_STATE, { history }),
};
//history可以分三種 主要在不同環境下儲存瀏覽的歷史
//createHashHistory 老舊瀏覽器
//createBrowserHistory 有支援HTML5
//createMemoryHistory nodejs後端 part
//這個 function 可以想做是換頁的時候因為是spa 所以只是把一些東西抽換掉
function updateTag(tagName, keyName, keyValue, attrName, attrValue) {
const node = document.head.querySelector(`${tagName}[${keyName}="${keyValue}"]`);
if (node && node.getAttribute(attrName) === attrValue) return;
// Remove and create a new tag in order to make it work with bookmarks in Safari
if (node) {
node.parentNode.removeChild(node);
}
if (typeof attrValue === 'string') {
const nextNode = document.createElement(tagName);
nextNode.setAttribute(keyName, keyValue);
nextNode.setAttribute(attrName, attrValue);
document.head.appendChild(nextNode);
}
}
...
//這邊主要就是把後端的東西 輸出到前端 因route.componet 會因為點連結而改變
ReactDOM.render(
<App context={context}>{route.component}</App>,
container,
() => onRenderComplete(route, location)
);
} catch (err) {
if (process.env.NODE_ENV !== 'production') {
throw err;
}
// Avoid broken navigation in production mode by a full page reload on error
console.error(err); // eslint-disable-line no-console
window.location.reload();
}
}
export default function main() {
//透過監聽history的改變來是否進行 撈取 universal
currentLocation = history.location;
history.listen(onLocationChange);
onLocationChange(currentLocation);
}
// Enable Hot Module Replacement (HMR) 程式碼有變動時會自動更新頁面
if (module.hot) {
module.hot.accept('./routes', () => {
routes = require('./routes').default; // eslint-disable-line global-require
currentLocation = history.location;
onLocationChange(currentLocation);
});
}
...
其他元件使用開發方法影片就有提到幾個 物件提升 大家可以參考一下,以上是基本目前理解的部分但還有許多還在摸索有興趣的朋友來一起來線上日常攻略讀書會 嚕